/**
 * Class:				WordDecoder.java
 * 
 * Project:				Bio-inspired car commander
 * 
 * Subproject:			Word Detector
 * 
 * Date: 				Mai - Juillet 2011
 * 
 * Auteurs:				Bruno Da Silva
 * 						Thomas Jordan
 * 
 * Description:
 * 
 *	Gère l'interaction entre la liste de mots, les MFCC extraites dans un fichier et le réseau
 * de neurones. Intervient notamment pour la création du dataset d'entrainement qui contient
 * le parrern d'activation. Ce dernier est dynamiquement créé à partir d'un fichier semblable
 * qui lui contient les mots en toutes lettre. Cela permet d'avoir un nombre de mots à reconnaitre
 * qui soit variable. 
 */
package mfccExtraction;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import ch.sda.bioinspiredcarcommander.words.WordsManager;
import android.app.Activity;
import android.util.Log;


public class WordDecoder {

	String binaryANNPath;
	String MFCC_FILE_L;
	String MFCC_FILE_P;
	String dynamicLearningDatasetPath;
	Activity act;
	WordsManager wm;
	LinkedList<String> internalDataset;
	Bkprop network;


	/**
	 * Load the binary neural network from fennix binary description file.
	 * @param binaryANNPath
	 * @param MFCC_FILE 
	 * @param dynamicLearningDatasetPath2 
	 * @param wm 
	 */
	public WordDecoder(String binaryANNPath, String MFCC_FILE_L, String MFCC_FILE_P, String dynamicLearningDatasetPath, Activity act, WordsManager wm){

		this.binaryANNPath = binaryANNPath;
		this.MFCC_FILE_L = MFCC_FILE_L;
		this.MFCC_FILE_P = MFCC_FILE_P;
		this.wm = wm;
		this.act = act;
		this.dynamicLearningDatasetPath = dynamicLearningDatasetPath;

		if(new File(MFCC_FILE_L).exists())
		{

			try {

				internalDataset = taductFeaturesToDataset();
				new File(dynamicLearningDatasetPath).delete();
				//Write it on the SDcard
				FileManager.ecrireFichier(dynamicLearningDatasetPath, internalDataset);

			} catch (IOException e) {
				e.printStackTrace();
			}
			//Initialise the MLP and give him the path to files he will need
			this.network = new Bkprop(wm.getWords().size(),dynamicLearningDatasetPath, MFCC_FILE_P);
		}

		//Try to deserialize the local ANN
		if(new File(MFCC_FILE_L).exists() && new File(binaryANNPath).exists())
		{
			network.InitializeNetworkFromFile(this.binaryANNPath);
			new File(dynamicLearningDatasetPath).delete();
		}

	}

	///////////////////////////
	//Getters
	///////////////////////////
	public Bkprop getNetwork() { return network; }

	public HashMap<String, Integer> getNbLearnSampleForWords(){

		
		HashMap<String, Integer>  occurencesCount = new HashMap<String, Integer>();
		LinkedList<String> learnFile = new LinkedList<String>();
		
		for(String word : wm.getWords())
		{
			occurencesCount.put(word, 0);
		}
		if(new File(MFCC_FILE_L).exists())
		{

			try {
				
				learnFile = FileManager.chargerFichier(MFCC_FILE_L);
				
				for(String line : learnFile)
				{
					String [] lineSplit = line.split(";");
					String currentW = lineSplit[lineSplit.length-1];
					occurencesCount.put(currentW, occurencesCount.get(currentW) +1);
				}
				
			} catch (IOException e) {
				e.printStackTrace();
			}
		}		 
		return occurencesCount;

	}

	//------------------------------------------------------

	public Bkprop trainMLP(Bkprop mlp)
	{
		mlp.init();
		mlp.training();
		return mlp;
	}


	public String evaluateMFCCs() throws FileNotFoundException
	{

		LinkedList<String> data = new LinkedList<String>();
		data = network.test();
		Log.v("LOL", data.getFirst());
		String translatedOutput = getOutputWordFromActivationPattern(data.getFirst());

		return translatedOutput;
	}


	private LinkedList<String> taductFeaturesToDataset() throws IOException {


		LinkedList<String> dataset = new LinkedList<String>();

		LinkedList<String> knowledgeBase = FileManager.chargerFichier(MFCC_FILE_L);

		String currentWord;
		int nbDiferentWords =  wm.getWords().size();

		//Brows the knowledge base, coolect lines, and traanslate text to outputcode for fennix
		for(String line : knowledgeBase)
		{
			//Split curent line to isolate the last term, the word associates
			String[] splittedLine = line.split(";");

			currentWord = splittedLine[splittedLine.length-1];

			//Look in the word list the position associate to the current line's word
			for(int pos = 0; pos < nbDiferentWords; pos++)
			{
				//If the current word matches, add the features and the value as output signature pattern
				if(currentWord.equals(wm.getWords().get(pos)))
				{

					//Get ann output pattern define by items in list for the application
					String outputsForFennix = getOutputActivationPattern(pos,nbDiferentWords);
					//Replace the word by the activation parrern					
					String lineModified =line.replace(currentWord,outputsForFennix);
					//Replace semicolon by tabs
					lineModified = lineModified.replace(";","\t");

					dataset.add(lineModified);
					break;
				}
			}
		}

		return dataset;
	}

	public static String getOutputActivationPattern(int pos, int nbPos) {

		String outputPattern ="";
		for(int i = 0; i < nbPos; i++)
		{
			if(i == pos)
				outputPattern+='\t' + "1";	
			else
				outputPattern+='\t' + "0";
		}

		//Remove the firts semicolon
		outputPattern = outputPattern.substring(1);
		return outputPattern;
	}

	private String getOutputWordFromActivationPattern(String outputParrern) {

		int cptPos = 0;
		int posBest = -1;
		double current;
		double max = Double.MIN_VALUE;

		for(String currentOut : outputParrern.split(","))
		{
			current = Double.parseDouble(currentOut);
			if(current > max)
			{
				max = current;
				posBest = cptPos;
			}
			cptPos++;
		}
		if(posBest != -1)

			return wm.getWords().get(posBest);
		else
			return "Somewthing's wrong!";

	}

	public void setNetwork(Bkprop bkprop) {
		this.network = bkprop;
	}

	public void generateDynamicDataset() {
		//Refresh the training base from learningbase.txt
		try {

			internalDataset = taductFeaturesToDataset();
			new File(dynamicLearningDatasetPath).delete();
			//Write it on the SDcard
			FileManager.ecrireFichier(dynamicLearningDatasetPath, internalDataset);

		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
}
